package org.triumphxx.logback;

import ch.qos.logback.classic.pattern.MessageConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: wangyp
 * @Date: 2023/11/6
 * @Time: 10:19
 * @Desc: 脱敏服务类
 **/

public class SensitiveConverter  extends MessageConverter {

    private static Logger log =   LoggerFactory.getLogger(SensitiveConverter.class);
    // 替换值
    public static final String KEY  = "**********";
    //表达是集合
    private static RegexReplacements regexReplacements;
    // 初始化规则
    static {
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        StringBuffer stringBuffer = new StringBuffer();
        try {
            inputStream=  SensitiveConverter.class.getClassLoader().getResourceAsStream("logback-filter.xml");
            inputStreamReader =  new InputStreamReader(inputStream);
            bufferedReader = new BufferedReader(inputStreamReader);
            String data;
            while ((data = bufferedReader.readLine()) != null){
                stringBuffer.append(data + "\n");
            }
        }catch (Exception e){
            log.error("读取配置文件出现异常"+e);
        }finally {
            try {
                inputStream.close();
                inputStreamReader.close();
                bufferedReader.close();
            }catch (IOException ioException){
                log.warn(ioException.getMessage());
            }
        }
        //将XmL转化为对象
        regexReplacements =  parseXml2Object(stringBuffer.toString(),RegexReplacements.class);

    }
    /**
     * 日志 替换
     * @param event
     * @return
     */
    @Override
    public String convert(ILoggingEvent event) {
        //初始日志
        String beginningLogInfo = event.getFormattedMessage();
        //脱敏后的日志
        return filterSensitive(beginningLogInfo);
    }

    /**
     * 进行脱敏
     * @param content
     * @return
     */
    private String filterSensitive(String content) {
        try {
            if (StringUtils.isBlank(content)){
                return content;
            }
            if (regexReplacements != null){
                //判断是否开启脱敏
                if (!regexReplacements.isSensitive()){
                    return content;
                }
                //获取脱敏规则
                List<RegexReplacement> replaces = regexReplacements.getReplace();
                if (!CollectionUtils.isEmpty(replaces)){
                    for (RegexReplacement replacement : replaces) {
                        //循环依次匹配脱敏规则
                        content = filterLog(content,replacement);
                    }
                }
            }
            return content;
        }catch (Exception e){
            return content;
        }
    }

    /**
     * 日志过滤
     * @param content
     * @param replacement
     * @return
     */
    private static String filterLog(String content, RegexReplacement replacement) {
        Pattern pattern = Pattern.compile(replacement.getRegex());
        return pattern.matcher(content).replaceAll(replacement.getReplacement());
    }

    /**
     * 日志过滤
     * @param content
     * @param replacement
     * @return
     */
    private static String filterLog2(String content, RegexReplacement replacement) {
        Pattern pattern = Pattern.compile(replacement.getRegex());
        Matcher matcher = pattern.matcher(content);
        StringBuffer stringBuffer = new StringBuffer();
        while (matcher.find()){
            matcher.appendReplacement(stringBuffer,baseSensitive(matcher.group(),replacement.getStartLength(),replacement.getEndLength()));
        }
        matcher.appendTail(stringBuffer);
        return stringBuffer.toString();
    }

    /**
     * 指定展示长度的脱敏处理
     * @param str
     * @param startLength
     * @param endLength
     * @return
     */
    private static String baseSensitive(String str, int startLength, int endLength) {
        if (StringUtils.isBlank(str)){
            return "";
        }
        String replacement = str.substring(startLength, str.length() - endLength);
        StringBuilder stringBuilder= new StringBuilder();
        for (int i = 0; i < replacement.length(); i++) {
            char ch = '0';
            if (replacement.charAt(i) >='0' && replacement.charAt(i) <='9'){
                ch = KEY.charAt(replacement.charAt(i)- '0');
            }else {
                replacement.charAt(i);
            }
            stringBuilder.append(ch);
        }
        return StringUtils.left(str,startLength)
                .concat(StringUtils.leftPad(StringUtils.right(str,endLength),
                        str.length()-startLength,stringBuilder.toString()));
    }



    /**
     * XML 转对象
     * @param xmlStr
     * @param targetClass
     * @return
     * @param <T>
     */
    private static<T> T parseXml2Object(String xmlStr, Class<T> targetClass) {
        JAXBContext jaxbContext = null;
        try {
            jaxbContext = JAXBContext.newInstance(targetClass);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            return (T)unmarshaller.unmarshal(new StringReader(xmlStr));
        }catch (JAXBException e){
            log.error("parseXml2Object has error"+e);
        }
        return null;
    }
}
